package com.sxd.bill.rela.item;

import java.util.Map;
import java.util.HashMap;
import java.util.Objects;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.apache.commons.text.StringSubstitutor;

import com.sxd.bill.common.enums.LabelNameEnum;
import com.sxd.bill.rela.util.RegexUtils;

public class Template {
    private final String template;
    private Pattern templatePattern;

    public Template(String template) {
        this.template = template;
    }

    public void reSetFilledTemplate() {
        templatePattern = null;
    }

    private int getMaxNumOfTemplate() {
        // 提取template中的数字, template示例:
        // "(?<tradingDirection>出|收|买|卖)${票据期限1}为主的${贴现人1}贴${承兑人1}及${票据期限2}${贴现人2}贴${承兑人}"
        Matcher m = Pattern.compile("\\$\\{[^\\{\\}]+?(?<num>\\d+)\\}").matcher(template);
        int maxNum = 0;
        while (m.find()) {
            int num = Integer.parseInt(m.group("num"));
            maxNum = Math.max(maxNum, num);
        }
        return maxNum;
    }

    /**
     * 填充模板方法，根据标签和表达式映射填充模板内容。
     * 
     * @param label2exp 标签和表达式的映射关系
     */
    public void fillTemplate(Map<LabelNameEnum, String> label2exp) {
        // 构造填充值的映射map
        Map<String, String> replaceMap = new HashMap<>();
        for (Map.Entry<LabelNameEnum, String> entry : label2exp.entrySet()) {
            LabelNameEnum labelNameEnum = entry.getKey();
            String exp = entry.getValue();
            //
            String key = labelNameEnum.getCnName();
            String groupName = labelNameEnum.getEnName(); // 切记：java的正则表达式中的组名只能由英文和数字构成（下划线也不行）
            String groupExpress = String.format("(?<%s>(?:%s)+)", groupName, exp);
            replaceMap.put(key, groupExpress);
        }
        // 若template中带填充的元素带数字后缀，则补充这些带数字后缀的元素的填充值
        int maxNum = getMaxNumOfTemplate();
        if (maxNum > 0) {
            for (Map.Entry<LabelNameEnum, String> entry : label2exp.entrySet()) {
                LabelNameEnum labelNameEnum = entry.getKey();
                String exp = entry.getValue();
                for (int i = 1; i <= maxNum; i++) {
                    String key = labelNameEnum.getCnName() + i;
                    String groupName = labelNameEnum.getEnName() + i;
                    String groupExpress = String.format("(?<%s>(?:%s)+)", groupName, exp);
                    replaceMap.put(key, groupExpress);
                }
            }
        }
        // 填充template中待填充元素(${xxx}标识)
        StringSubstitutor sub = new StringSubstitutor(replaceMap);
        String filledTemplate = sub.replace(template);
        try {
            templatePattern = Pattern.compile(filledTemplate);
        } catch (PatternSyntaxException e) {
            // e.printStackTrace();
            templatePattern = null;
        }
    }

    public TemplateResult extract(String text) {
        if (Objects.isNull(templatePattern)) {
            return TemplateResult.ofEmpty();
        }
        // 获取分组名
        List<String> groupNames = RegexUtils.getGroupNames(this.templatePattern.pattern());
        // 正则抽取
        Matcher m = templatePattern.matcher(text);
        if (m.find()) {
            String matchedText = m.group();
            int startIndex = m.start();
            int endIndex = m.end();
            Map<String, String> foundGroup = new HashMap<>();
            for (String groupName : groupNames) {
                try {
                    String value = m.group(groupName);
                    foundGroup.put(groupName, value);
                } catch (Exception e) {
                    // 加日志
                    continue;
                }
            }
            return new TemplateResult(foundGroup, matchedText, startIndex, endIndex, text);
        } else {
            return TemplateResult.ofEmpty();
        }

    }

}
